package com.leyou.item.service;


import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.utils.LevelUtil;
import com.leyou.item.dao.AclModuleMapper;
import com.leyou.item.dto.AclModuleLevelDto;
import com.leyou.item.pojo.AclModule;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import java.util.*;

/**
 * @author:yanjizhw@163.com
 * @date:2019-10-12 9:03
 * 描述:
 * @since:1.0.0
 */
@Service
public class AclModuleService {

    @Autowired
    private AclModuleMapper aclModuleMapper;

    public void save(AclModule aclModule){

        checkExist(aclModule.getParent_id(), aclModule.getName());

        aclModule.setId(null);
        aclModule.setLevel(LevelUtil.calculateLevel(getLevel(aclModule.getParent_id()), aclModule.getParent_id()));
        aclModule.setOperator("admin");
        aclModule.setOperate_time(new Date());
        aclModule.setOperate_ip("127.0.0.1");

        aclModuleMapper.insertSelective(aclModule);
    }

    public List<AclModuleLevelDto> queryAclModuleTree() {

        List<AclModule> aclModules = aclModuleMapper.selectAll();

        List<AclModuleLevelDto> dtoList = new ArrayList<>();

        for (AclModule aclModule : aclModules){
            dtoList.add(AclModuleLevelDto.adapt(aclModule));
        }

        return AclModuleListToTree(dtoList);
    }

    public List<AclModuleLevelDto> AclModuleListToTree(List<AclModuleLevelDto> dtoList) {
        if (CollectionUtils.isEmpty(dtoList)) {
            return new ArrayList();
        }
        // level -> [aclmodule1, aclmodule2, ...] Map<String, List<Object>>
        Multimap<String, AclModuleLevelDto> levelAclModuleMap = ArrayListMultimap.create();
        List<AclModuleLevelDto> rootList = new ArrayList();

        for (AclModuleLevelDto dto : dtoList) {
            levelAclModuleMap.put(dto.getLevel(), dto);
            if (LevelUtil.ROOT.equals(dto.getLevel())) {
                rootList.add(dto);
            }
        }
        Collections.sort(rootList, aclModuleSeqComparator);
        transformAclModuleTree(rootList, LevelUtil.ROOT, levelAclModuleMap);
        return rootList;
    }

    public void transformAclModuleTree(List<AclModuleLevelDto> dtoList, String level, Multimap<String, AclModuleLevelDto> levelAclModuleMap) {
        for (int i = 0; i < dtoList.size(); i++) {
            AclModuleLevelDto dto = dtoList.get(i);
            String nextLevel = LevelUtil.calculateLevel(level, dto.getId());
            List<AclModuleLevelDto> tempList = (List<AclModuleLevelDto>) levelAclModuleMap.get(nextLevel);
            if (CollectionUtils.isNotEmpty(tempList)) {
                Collections.sort(tempList, aclModuleSeqComparator);
                dto.setAclModuleList(tempList);
                transformAclModuleTree(tempList, nextLevel, levelAclModuleMap);
            }
        }
    }

    public Comparator<AclModuleLevelDto> aclModuleSeqComparator = new Comparator<AclModuleLevelDto>() {
        public int compare(AclModuleLevelDto o1, AclModuleLevelDto o2) {
            return o1.getSeq() - o2.getSeq();
        }
    };


    private void checkExist(Integer parentId, String aclModuleName) {
        Example example = new Example(AclModule.class);
        example.createCriteria().andEqualTo("parent_id", parentId)
                .andEqualTo("name", aclModuleName);
        List<AclModule> aclModules = aclModuleMapper.selectByExample(example);

        if (CollectionUtils.isNotEmpty(aclModules)){
            throw new LyException(ExceptionEnum.ACL_MODULE_SAME_NAME);
        }
    }

    private String getLevel(Integer aclModuleId) {
        AclModule aclModule = aclModuleMapper.selectByPrimaryKey(aclModuleId);
        if (aclModule == null) {
            return null;
        }
        return aclModule.getLevel();
    }

    public List<AclModule> querySelect() {

        Example example = new Example(AclModule.class);

        Example.Criteria criteria = example.createCriteria();

        criteria.andEqualTo("is_parent", 1);

        return aclModuleMapper.selectByExample(example);

    }
}
